/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.service;


import com.inspur.edp.bef.bemanager.codegenerator.JavaCodeFileGenerator;
import com.inspur.edp.bef.bemanager.codegenerator.genutils.BeCommonUtilsGenerator;
import com.inspur.edp.bef.bemanager.generatecomponent.ComponentGenerator;
import com.inspur.edp.bef.bemanager.generatedbo.DboGenerater;
import com.inspur.edp.bef.bemanager.util.CheckInfoUtil;
import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.beenum.BECategory;
import com.inspur.edp.bef.bizentity.dtservice.IBizEntityDtService;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.component.base.GspComponent;
import com.inspur.edp.cef.designtime.api.element.EnumIndexType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.entity.MappingInfo;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.common.ConvertUtils;
import com.inspur.edp.jittojava.context.GenerateService;
import com.inspur.edp.lcm.databaseobject.api.DatabaseObjectServiceForWebIde;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.devcommon.ManagerUtils;
import com.inspur.edp.sgf.api.common.ResourceType;
import com.inspur.edp.sgf.api.service.EapiMetadataDtService;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID;
import java.util.regex.Matcher;
import org.springframework.util.StringUtils;

public class BeManagerService implements IBizEntityDtService {

  private static MetadataService metadataService;

  public static MetadataService getMetadataService() {
    if (metadataService == null) {
      metadataService = SpringBeanUtils.getBean(MetadataService.class);
    }
    return metadataService;
  }

  public static void saveMetadata(GspMetadata metadata, String metadataPath) {
    getMetadataService().saveMetadata(metadata,
        CheckInfoUtil.getCombinePath(metadataPath, metadata.getHeader().getFileName()));
  }
  // 工程路径

  public static String getProjPath(String relativePath) {
    MetadataProjectService service = getMetadataProjectService();
    return service.getProjPath(relativePath);
  }

  private static MetadataProjectService metadataProjectService;

  public static MetadataProjectService getMetadataProjectService() {
    if (metadataProjectService == null) {
      metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class);
    }
    return metadataProjectService;
  }

  private static GenerateService generateService;

  public static GenerateService getGenerateService() {
    if (generateService == null) {
      generateService = SpringBeanUtils.getBean(GenerateService.class);
    }
    return generateService;
  }


  public static void generateDbo(GspMetadata metadata, String metadataPath, boolean isSave) {
    GspBusinessEntity be = (metadata.getContent() instanceof GspBusinessEntity)
        ? metadata.getContent() : null;
    if (be.getCategory() == BECategory.DependentBusinessEntity) {
      return;
    }
    DboGenerater dboGenerater = new DboGenerater(metadataPath);
    dboGenerater.GenerateDboFromBizEntity(be, metadataPath);

    if (isSave) {
      saveMetadata(metadata, metadataPath);
    }
  }

  public static ArrayList<String> generateComponent(GspMetadata metadata, String metadataPath,
      boolean isSave) {
    return ComponentGenerator.getInstance().generateComponent(metadata, metadataPath);
  }

  public static void generateComponentCode(GspMetadata metadata, String metadataPath,
      ArrayList<String> actionList) {
    String ProjectPath = metadata.getRelativePath();
    //ProjectPath = ProjectPath.Remove(ProjectPath.LastIndexOf("/"), ProjectPath.Length - (ProjectPath.LastIndexOf("/")));
    new JavaCodeFileGenerator(metadata).generate(actionList);
    if (actionList != null && actionList.size() > 0) {
      new BeCommonUtilsGenerator((GspBusinessEntity) metadata.getContent(), metadata)
          .generateCommonUtils();
    }
  }

  /**
   * 判断当前是否创建Java模板，创建返回值为true,不能创建返回flase;
   *
   * @param
   * @return
   */
  public static boolean CreatJavaModule(String ProjectPath) {
    return true;
  }

  /**
   * 判断当前是否创建dotnet模板，创建返回值为true,不能创建返回flase;
   *
   * @param
   * @return
   */
  public static boolean CreatDotnetModule(String ProjectPath) {
    return false;
  }

  public static void preBuild(GspMetadata metadata, String metadataPath) {
    //BEGeneratorService service = new BEGeneratorService();
    //service.PreGenerate(metadataPath, metadata);

    try {
      SpringBeanUtils.getBean(GenerateService.class).generateApi(metadataPath);
    } catch (Exception e) {
      throw new RuntimeException("");
    }
//		ServiceManager.<MetadataJitService>GetService().GenerateApi(metadataPath);
  }

  public static void build(GspMetadata metadata, String metadataPath) {
    build(metadata, metadataPath, null);
  }

  public static void build(GspMetadata metadata, String metadataPath, String serverPath) {
    throw new UnsupportedOperationException();
  }

  public static void publish(GspMetadata metadata, String metadataPath) {
    GspBusinessEntity be = (metadata.getContent() instanceof GspBusinessEntity)
        ? metadata.getContent() : null;

    if (be.getCategory() != BECategory.DependentBusinessEntity) {
      DeployDbo(be, metadataPath);
    }
    //Build(metadata, metadataPath);
  }

  /**
   * 发布dbo
   *
   * @param be
   * @param path
   */
  private static void DeployDbo(GspBusinessEntity be, String path) {
    DatabaseObjectServiceForWebIde service = SpringBeanUtils
        .getBean(DatabaseObjectServiceForWebIde.class);

    service.deployDatabaseObject(path, be.getMainObject().getRefObjectName());

    if (be.getMainObject().getContainChildObjects() == null
        || be.getMainObject().getContainChildObjects().size() < 1) {
      return;
    }
    for (IGspCommonObject childObject : be.getMainObject().GetAllChildObjects()) {
      service.deployDatabaseObject(path, childObject.getRefObjectName());
    }
  }

  public static void publishService(GspMetadata metadata, String metadataPath) {
    createViewMode(metadata, metadataPath);
  }

  ///#region Vm&Service
  private static final String VmSuffix = "Service";

  private static void createViewMode(GspMetadata metadata, String path) {
    String metadataName = metadata.getHeader().getCode();
    //var be = metadata.Content as GspBusinessEntity;
    String vmPath = getVmPath(path);
    MetadataService service = SpringBeanUtils.getBean(MetadataService.class);
    String vmFileName = String.format("%1$s%2$s.vo", metadataName, VmSuffix);

    GspMetadata vmMetadata;
    if (service.isMetadataExist(vmPath, vmFileName)) {
      vmMetadata = updateViewModel(metadata, vmFileName, vmPath, service);
    } else {
      vmMetadata = createViewMode(metadata, metadataName, vmPath, service);
    }

    //VmGeneratorService.Generate(vmPath, vmMetadata);
    EapiMetadataDtService eapiService = SpringBeanUtils.getBean(EapiMetadataDtService.class);

    eapiService.create(vmMetadata, vmPath, ResourceType.VO_ADVANCE);
  }

  private static String getVmPath(String path) {
    MetadataProject projectInfo = SpringBeanUtils.getBean(MetadataProjectService.class)
        .getMetadataProjInfo(path);
    String projectPath = projectInfo.getProjectPath();
    //var vmPath = Path.Combine(projectPath, "form", metadataName.ToLower(), "bff");

    String vmPath = CheckInfoUtil.getCombinePath(projectPath, "bff");

    FileService fileService = SpringBeanUtils.getBean(FileService.class);
    if (!fileService.isDirectoryExist(vmPath)) {
      fileService.createDirectory(vmPath);
    }

    return vmPath;
  }

  private static GspMetadata updateViewModel(GspMetadata metadata, String vmFileName, String vmPath,
      MetadataService service) {

    GspBusinessEntity be = (metadata.getContent() instanceof GspBusinessEntity)
        ? metadata.getContent() : null;
    GspMetadata vmMetadata = service.loadMetadata(vmFileName, vmPath);
    GspViewModel vm = ConvertUtils.convertToViewModel(be, "", metadata.getHeader().getId());
    vm.setID(vmMetadata.getHeader().getId());
    vmMetadata.setContent(vm);
    service.saveMetadata(vmMetadata, CheckInfoUtil.getCombinePath(vmPath, vmFileName));

    return vmMetadata;
  }

  private static GspMetadata createViewMode(GspMetadata metadata, String metadataName,
      String vmPath, MetadataService service) {

    GspBusinessEntity be = (metadata.getContent() instanceof GspBusinessEntity)
        ? metadata.getContent() : null;
    GspViewModel vm = ConvertUtils.convertToViewModel(be, "", metadata.getHeader().getId());
    GspMetadata vmMetadata = new GspMetadata();

    vmMetadata.setHeader(metadata.getHeader());
    vmMetadata.getHeader().setId("");
    vmMetadata.getHeader().setCode(String.format("%1$s%2$s", metadataName, VmSuffix));
    vmMetadata.getHeader().setName(vm.getName());
    vmMetadata.getHeader().setType("GspViewModel");
    vmMetadata = service.initializeMetadataEntity(vmMetadata);

    vm.setID(vmMetadata.getHeader().getId());
    vmMetadata.setContent(vm);

    service.createMetadata(vmPath, vmMetadata);
    return vmMetadata;
  }


  public static void Deploy(String metadataPath) {

//		var metadataProj = ServiceManager.<IMetadataProjectService>GetService().GetMetadataProjInfo(metadataPath);
//		String projectPath = Path.Combine(PathTransform.GetUserProjectsRoot(), metadataProj.ProjectPath).Replace("\\","/");
//		String deployToolPath = Path.Combine(GspEnvironment.RootPath, "platform/dev/main/libs/BefDeployer.dll").Replace("\\","/");
//
//		//IsProjectExists(projectPath);
//		//var command = "../netcore/windows/dotnet.exe";
//		String command = "dotnet";
//		ProcessStartInfo tempVar = new ProcessStartInfo(command, " " + deployToolPath + " -s " + projectPath);
//		tempVar.CreateNoWindow = false;
//		tempVar.UseShellExecute = true;
//		tempVar.ErrorDialog = true;
//		tempVar.WorkingDirectory = Path.GetFullPath(Path.Combine(GspEnvironment.RootPath, "platform/dev/main/libs/")).Replace("\\", "/");
//		ProcessStartInfo psi = tempVar;
//			//RedirectStandardInput = false,
//			//RedirectStandardOutput = false,
//			//RedirectStandardError = true,
//		Process.Start(psi);
  }

  ///#region IBizEntityDtService
  public void generateDbo(GspMetadata metadata, String metadataPath) {
    generateDbo(metadata, metadataPath, true);
  }

  @Override
  public GspBizEntityElement createUdtElement(String id, String code, String name, String labelId,
      String udtId) {
    Objects.requireNonNull(code, "code");
    Objects.requireNonNull(name, "name");
    Objects.requireNonNull(labelId, "labelId");
    Objects.requireNonNull(udtId, "udtId");

    if (StringUtils.isEmpty(id)) {
      id = UUID.randomUUID().toString();
    }

    GspMetadata metadata = MetadataUtil.getCustomMetadata(udtId);
    if (metadata == null) {
      throw new RuntimeException("udt元数据不存在:" + udtId);
    }
    UnifiedDataTypeDef udtDef = (UnifiedDataTypeDef) metadata.getContent();
    if (udtDef == null) {
      throw new RuntimeException("udt元数据不存在:" + udtId);
    }
    if (!(udtDef instanceof SimpleDataTypeDef)) {
      throw new RuntimeException("暂不支持多值udt:" + udtDef.getName());
    }
    SimpleDataTypeDef simpleUdt = (SimpleDataTypeDef) udtDef;
    GspBizEntityElement rez = new GspBizEntityElement() {{
      setCode(code);
      setName(name);
      setLabelID(labelId);
      setIsUdt(true);
      setUdtID(udtId);
      setUdtName(udtDef.getName());
      setObjectType(simpleUdt.getObjectType());
      setMDataType(simpleUdt.getMDataType());
      setLength(simpleUdt.getLength());
      setPrecision(simpleUdt.getPrecision());
    }};

    rez.setID(id);
    switch (simpleUdt.getObjectType()) {
      case None:
        break;
      case Enum:
        rez.setEnumIndexType(EnumIndexType.Integer);
        rez.setContainEnumValues(simpleUdt.getContainEnumValues().clone());
        break;
      default:
        throw new RuntimeException("暂不支持此类型的Udt" + simpleUdt.getObjectType());
    }

    rez.getChildElements().add(new GspBizEntityElement() {{
      setID(UUID.randomUUID().toString());
      setLabelID(labelId + "_" + simpleUdt.getContainElements().get(0).getLabelID());
      setCode(code + "_" + simpleUdt.getContainElements().get(0).getCode());
      setIsRef(false);
      setObjectType(GspElementObjectType.None);
      setMDataType(simpleUdt.getMDataType());
      setLength(simpleUdt.getLength());
      setPrecision(simpleUdt.getPrecision());
    }});

    rez.getMappingRelation().add(new MappingInfo() {{
      setKeyInfo(rez.getChildElements().get(0).getID());
      setValueInfo(rez.getUdtID());
    }});
    return rez;
  }

  ///#endregion

  //region 生成构件和代码
  public static GspMetadata createCompCode(String path, String bizObjectId, String nodeCode,
      boolean isChild, GspBusinessEntity be, BizOperation operation) {
    //生成构件元数据
    GspMetadata compMeta = ComponentGenerator.getInstance().createCompByOperation(
        operation, path, be.getCode(), isChild, nodeCode, bizObjectId);
    operation.setComponentId(compMeta.getHeader().getId());
    operation.setComponentName(compMeta.getHeader().getCode());
    //生成java代码
    JavaCodeFileGenerator javaCodeFileGenerator = new JavaCodeFileGenerator(path, be);
    javaCodeFileGenerator.createJavaCodeFile(operation, isChild, nodeCode);
    return compMeta;
  }

  public static String getCodePath(String projectpath, GspMetadata compMetaData) {
    IMetadataContent content = compMetaData.getContent();
    String javaClass = ((GspComponent) content).getMethod().getClassName();

    String str = ManagerUtils.getRalativePath(
        SpringBeanUtils.getBean(MetadataProjectService.class).getProjPath(projectpath));
    str = str.replace("/", "\\");

    javaClass = javaClass.replace(".", "\\");
    String filePath = str + "\\java\\code\\comp\\src\\main\\java\\" + javaClass + ".java";
    filePath = filePath.replaceAll("\\\\", Matcher.quoteReplacement(File.separator));
    filePath = filePath.replaceAll("/", Matcher.quoteReplacement(File.separator));
    return filePath;
  }

  // 获取是工程类型（生成型工程 or 解析型工程）
  public static ProcessMode getProjectProcessMode(String path) {
    MetadataProjectService service = getMetadataProjectService();
    return service.getProcessMode(getProjPath(path));
  }

  // 生成pom文件
  public static void generatePom(String path, String bizEntityName) {
    GenerateService service = getGenerateService();
    try {
      service.generate(getProjPath(path));
    } catch (Exception e) {
      throw new RuntimeException("业务实体【" + bizEntityName + "】生成 pom 文件失败", e);
    }
  }

  //endregion
}
